import axios from 'axios'
import qs from 'qs'
import _ from 'lodash'

// 服务地址
let service = axios.create({
    baseURL: '',
    withCredentials: true
});


// request interceptor
service.interceptors.request.use(
  config => {
      // do something before request is sent
      const URL_ARR = config.url.split('/')
      const API_PREFIX = URL_ARR[1]
      if (global.API_PREFIX_CONFIG[API_PREFIX] === undefined) {
          if (!list.some(i => i === config.url)) list.push(config.url)
          if (list.length) {
              // console.log(list)
          }
      }
      URL_ARR[1] = global.API_PREFIX_CONFIG[API_PREFIX] === undefined ? URL_ARR[1] : global.API_PREFIX_CONFIG[API_PREFIX]

      config.url = URL_ARR.filter(item => item).join('/')

      // 如果是get请求 参数增加时间戳，否则ie可能会不走服务器从缓存拿数据
      if (config.method.toLowerCase() === 'get') {
          const t = new Date().getTime()
          if (config.params) {
              config.params['t'] = t
          } else {
              if (config.url.indexOf('?') > -1) {
                  config.url += `&t=${t}`
              } else {
                  config.url += `?t=${t}`
              }
          }
      }
      return config
  },
  error => {
      console.log(error)
      return Promise.reject(error)
  }
)

// response interceptor
service.interceptors.response.use(
  response => {
      resolveRequest(response)
      if (response.config.responseType === 'blob') {
          return response
      } else {
          // 统一处理业务
          return response
      }
  },
  error => {
      // console.log('err', error.response, error.message) // for debug
      let msg = error.message || '系统出错'
      console.log(error)
      handleErrorRequest(error)
      if (error.response) {
          // console.log(error.response.data)
          // 统一处理拦截业务
      }
      return msg
  }
)


/**
 * 封装get方法
 * @param url
 * @param params
 * @returns {Promise}
 */
export function fetchGet (url, params = {}) {
    return new Promise((resolve, reject) => {
        service.get(url, {
            params: params
        }).then(response => {
            resolve(response.data);
        }).catch(err => {
            reject(err)
        })
    });
}

/**
 * 封装fetchJson(请求本地静态JSON文件)
 * @param {*} url
 * @param {*} params
 */
export function fetchJson(url, params = {}, config) {
    return new Promise((resolve, reject) => {
        service.get(url, {
            params: params,
            baseURL: '' // 请求本地JSON文件,不需要proxy代理
        }).then(response => {
            resolve(response.data);
        }, err => {
            reject(err);
        })
    })
}


/**
 * 封装post请求(以formData提交)
 * @param url
 * @param params
 * @param config (相关请求配置,默认为{})
 * @returns {Promise}
 */
export function fetchFD(url, params = {}, config) {
    let _config = config || {};

    // 转换成FormData形式,传递参数给后台
    if (Object.prototype.toString.call(params) === "[object Object]") {
        let formData = new FormData();
        for (let key in params) {
            if (params.hasOwnProperty(key)) {
                formData.append(key, params[key]);
            }
        }
        return new Promise((resolve, reject) => {
            service.post(url, formData, _config)
              .then(response => {
                  resolve(response.data);
              }, err => {
                  reject(err);
              })
        })
    } else {
        console.log('传递的参数为对象形式!');
    }
}

/**
 * 封装fetchPost(以JSON形式提交)
 * @param {*} url
 * @param {*} params
 * @param {*} config
 */
export function fetchPost(url, params = {}, config) {
    let _config = config || {};
    return new Promise((resolve, reject) => {
        service.post(url, params, _config)
          .then(response => {
              resolve(response.data);
          }, err => {
              reject(err);
          })
    })
}


const requestTimeout = {}
const requestQueue = new Map()
const requestTime = 3000 // 同一个请求，requestTime时间没有响应，从队列中删除
const resultSaveTime = 1500 // 同一个请求&&参数相同，结果缓存时间

const addTimeout = (requestId) => {
    requestTimeout[requestId] = setTimeout(() => {
        requestQueue.delete(requestId)
        try {
            delete requestTimeout[requestId]
        } catch (e) {}
    }, requestTime)
}
const removeTimeout = (requestId) => {
    requestTimeout[requestId] && clearTimeout(requestTimeout[requestId])
    try {
        delete requestTimeout[requestId]
    } catch (e) {}
}
const deleteTimeStamp = (url) => {
    const urlArr = url.split('?')
    if (urlArr.length === 2) {
        let urlParams = urlArr[1]
        const reg = /^(.*?)(&?t=\d+)(&?.*?)$/g
        const regResult = reg.exec(urlParams)
        if (regResult) {
            urlParams = regResult[1] + regResult[3]
        }
        if (urlParams) {
            urlParams = '?' + urlParams
        }
        url = urlArr[0] + urlParams
    }
    return url
}

const handleParamsData = (data) => {
    let str = ''
    const dataType = Object.prototype.toString.call(data)
    if (dataType === '[object String]') {
        try {
            str = qs.stringify(JSON.parse(data))
        } catch (e) {
            // console.log('config.data不能被解析')
            str = data
        }
    } else {
        str = qs.stringify(data)
    }
    return str
}

function handleRequestId(config) {
    // 通过config，生成当前request的id
    // id通过 method（请求类型）、url(请求地址)、params（请求参数，一般是get请求使用）、data（请求参数，一般是post请求使用）

    // 去除get请求默认添加的时间戳
    const configParams = config?.['params'] || {}
    // 将设置复制一份，避免改动原接口请求
    let copyConfig = {
        url: config.url,
        params: { ...configParams },
        method: config.method.toLowerCase(),
        data: handleParamsData(config.data)
    }
    let url = deleteTimeStamp(copyConfig.url)

    if (copyConfig?.['params']?.hasOwnProperty('t')) {
        delete copyConfig.params.t
    }
    url = url.replace(/(\/)+/g, '/')
    copyConfig.url = url

    const params = qs.stringify(copyConfig.params)
    const paramsData = copyConfig.data
    return [
        copyConfig.method,
        url,
        params,
        paramsData
    ].join('&')
}

const handleErrorRequest = (response) => {
    if (!requestQueue.size) {
        return
    }
    const { config } = response
    const requestId = handleRequestId(config)
    if (requestQueue.has(requestId)) {
        const waitResultArr = requestQueue.get(requestId) || []
        if (waitResultArr.length > 0) {
            waitResultArr.forEach(resolve => {
                resolve({})
            })
        }
        removeTimeout(requestId)
        requestQueue.delete(requestId)
        console.log('当前requestQueue数量', requestQueue.size)
    } else {
        console.log(requestId)
        // console.log(requestQueue)
        console.log(response)
    }
}

const resolveRequest = (response) => {
    if (!requestQueue.size) {
        return
    }
    const { config, data } = response

    const requestId = handleRequestId(config)
    if (requestQueue.has(requestId)) {
        const requestItem = requestQueue.get(requestId)
          .set('status', 'success')
          .set('result', { ...data })
        const callback = requestItem.get('callback')
        if (callback.length > 0) {
            callback.forEach(resolve => {
                // console.log('处理waitResult', requestId)
                resolve(_.cloneDeep(data || {}))
            })
        }
        removeTimeout(requestId)
        setTimeout(() => {
            requestQueue.delete(requestId)
            console.log('当前requestQueue数量', requestQueue.size)
        }, resultSaveTime)
    } else {
        console.log(requestId)
        // console.log(requestQueue)
        console.log(response)
    }
}

const requestService = (config) => {
    const requestId = handleRequestId(config)
    if (!requestQueue.has(requestId)) {
        const requestItem = new Map()
          .set('callback', [])
          .set('status', 'pending')
        requestQueue.set(requestId, requestItem)
        console.log('当前requestQueue数量', requestQueue.size)
        addTimeout(requestId)
        return service(config)
    } else {
        const requestItem = requestQueue.get(requestId)
        return new Promise(resolve => {
            const status = requestItem.get('status')
            // console.log(status)
            if (status === 'success') {
                // 有缓存结果，直接返回
                // console.log('有缓存结果，直接返回')
                const result = _.cloneDeep(requestItem.get('result') || {})
                resolve(result)
            } else {
                // console.log('新增waitResult', requestId)
                const callback = requestItem.get('callback')
                callback.push(resolve)
                requestItem.set('callback', callback)
                requestQueue.set(requestId, requestItem)
            }
        })
    }
}
// 路由变动清空请求队列
window.addEventListener('hashchange', () => {
    // console.log('hashchange清空队列')
    requestQueue.clear()
})
window.addEventListener('popstate', () => {
    // console.log('popstate清空队列')
    requestQueue.clear()
})

export default requestService
